// TODO: CODE REVIEW & CLEANUP!
//
// MusicSaveQueueScreen.xaml.cs
//

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml;
using HomeUX.ClientControlSupport;
using HomeUX.Synchronization;
using HomeUX.Utilities;

namespace HomeUX.MusicClientLibrary
{

public partial class MusicSaveQueueScreen : UserControl
{
    MusicClientHelper _musicClientHelper;

    /// <summary>
    /// Contains the names of existing playlists, or <n>null</n> if the list hasn't been loaded
    /// from the server yet.  Values are all <n>true</n>.
    /// </summary>
	Dictionary<string, bool> _existingPlaylistNames = null;

    SyncNode _queueSaveStateNode;

    /// <summary>
    /// Set to <n>true</n> if <r>InitializePlaylistName</r> was called but it couldn't complete
    /// because <
    /// </summary>
    bool _playlistNamePendingInitialization;

    /// <summary>
    /// A <n>String.Format</n>-style format string to use for <n>HeaderTextBlock</n>.  Initialized
    /// from the design-time text value of  <n>HeaderTextBlock</n>.
    /// </summary>
    string _headerFormatString;

    public MusicSaveQueueScreen()
    {
        InitializeComponent();

        // initialize <_headerFormatString>
        _headerFormatString = HeaderTextBlock.Text;

        Loaded += MusicSaveQueueScreen_Loaded;
    }

    void MusicSaveQueueScreen_Loaded(object sender, RoutedEventArgs e)
    {
        _musicClientHelper = new MusicClientHelper(this, BeginLoadingDataFromMusicServer,
            OnParcelReceived);

        HeaderTextBlock.Text = String.Format(_headerFormatString, _musicClientHelper.MusicDeviceName);

        _musicClientHelper.LoadingMessage = "Please wait...";
        _musicClientHelper.Screen.Opened += OnScreenOpened;

        _queueSaveStateNode = (SyncNode)_musicClientHelper.MusicDeviceNode.CreateNode(
            SyncPath.FromString("QueueSaveState"));
        _queueSaveStateNode.ValueChanged += delegate
        {
            OnQueueSaveStateChanged();
            if (_playlistNamePendingInitialization)
                InitializePlaylistName();
        };
        if (_queueSaveStateNode.Value != null)
            OnQueueSaveStateChanged();
    }

    void InitializePlaylistName()
    {
        if (_queueSaveStateNode.Value != null)
        {
            // populate the playlist name text box with the name of the playlist associated with the
            // queue, if any
            _playlistNamePendingInitialization = false;
            QueueSaveState queueSaveState;
            string associatedPlaylistName;
            MusicQueueScreen.ParseQueueSaveState(_queueSaveStateNode, out queueSaveState, out associatedPlaylistName);
            if (!String.IsNullOrEmpty(associatedPlaylistName))
            {
                PlaylistNameTextBox.Text = associatedPlaylistName;
                PlaylistNameTextBox.TextBox.SelectAll();
            }
            else
                PlaylistNameTextBox.Text = String.Empty;
        }
        else
            _playlistNamePendingInitialization = true;

    }

    void OnScreenOpened(object sender, EventArgs e)
    {
        InitializePlaylistName();

        // do the same thing we'd do if we were waiting for the music server to become available
        _musicClientHelper.TryToLoadData();
    }

    void BeginLoadingDataFromMusicServer()
    {
        string command = ParsedSyncNodeCommand.Format("GetPlaylists",
            "RecipientId", XmlConvert.ToString(_musicClientHelper.RecipientId));
        _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);
    }

    void OnParcelReceived(Guid recipientId, XmlReader reader)
    {
        // do nothing if we're in an error state
        if (_musicClientHelper.LoadState == MusicClientLoadState.Error)
            return;

        try
        {
            foreach (XmlElementInfo element in XmlElementInfo.EnumerateElements(reader))
            {
                switch (element.Name)
                {

                case "Playlists":

                        if (_existingPlaylistNames == null)
						{
                            _existingPlaylistNames = new Dictionary<string, bool>(
								StringComparer.CurrentCultureIgnoreCase);
						}
                        else
                            _existingPlaylistNames.Clear();
					break;

                case "Playlist":

                    _existingPlaylistNames[element.GetRequiredAttribute("Name")] = true;
                    break;

                case "/Playlists":

                    UpdateSaveEnabledState();

                    // once we've loaded the list of playlists we can enable the text box used to
                    // enter the playlist name -- until then we can't validate that an entered
                    // playlist name isn't already in use
                    PlaylistNameTextBox.IsEnabled = true;

                    _musicClientHelper.OnDataLoaded();
                    PlaylistNameTextBox.Focus();
                    break;
                }
            }
        }
        catch (InvalidOperationException ex)
        {
            ClientGlobals.Alert(AlertType.Warning,
                "Invalid reply from server: {0}", ex.Message);
        }
    }

    void OnQueueSaveStateChanged()
    {
        QueueSaveState queueSaveState;
        string associatedPlaylistName;

        MusicQueueScreen.ParseQueueSaveState(_queueSaveStateNode, out queueSaveState, out associatedPlaylistName);
        switch (queueSaveState)
        {
        case QueueSaveState.NewEmpty:
            CurrentPlaylistStateTextBlock.Text = "Queue has not been saved and is empty";
            CurrentPlaylistNameTextBlock.Text = String.Empty;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Collapsed;
            break;
        case QueueSaveState.NewNotEmpty:
            CurrentPlaylistStateTextBlock.Text = "Queue has not been saved";
            CurrentPlaylistNameTextBlock.Text = String.Empty;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Collapsed;
            break;
        case QueueSaveState.Loaded:
            CurrentPlaylistStateTextBlock.Text = "Queue was loaded from this playlist, and wasn't modified since then:";
            CurrentPlaylistNameTextBlock.Text = associatedPlaylistName;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Visible;
            break;
        case QueueSaveState.LoadedModified:
            CurrentPlaylistStateTextBlock.Text = "Queue was loaded from this playlist, and was modified since then:";
            CurrentPlaylistNameTextBlock.Text = associatedPlaylistName;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Visible;
            break;
        case QueueSaveState.Saved:
            CurrentPlaylistStateTextBlock.Text = "Queue was saved to this playlist, and wasn't modified since then:";
            CurrentPlaylistNameTextBlock.Text = associatedPlaylistName;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Visible;
            break;
        case QueueSaveState.SavedModified:
            CurrentPlaylistStateTextBlock.Text = "Queue was saved to this playlist, and was modified since then:";
            CurrentPlaylistNameTextBlock.Text = associatedPlaylistName;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Visible;
            break;
        default:
            break;
        }

        UpdateSaveEnabledState();
    }

    void UpdateSaveEnabledState()
    {
        // disable Save if we haven't loaded playlist names yet -- but don't show a warning
        // message, since this is likely a transient state
        if (_existingPlaylistNames == null)
        {
            SaveButton.IsEnabled = false;
            CannotSaveMessage.Text = String.Empty;
            return;
        }

        // disable Save if the playlist name is empty -- but don't show a warning message, because
        // that's a relatively obvious situation
        if (PlaylistName.Length == 0)
        {
            SaveButton.IsEnabled = false;
            CannotSaveMessage.Text = String.Empty;
            return;
        }

        // set <isSavedPlaylist> to true if the entered playlist name is the same as the playlist
        // name that was last loaded to or saved from; note that this test is imperfect because
        // the culture used for string comparisons on the music server may not match the culture
        // of this machine, but in the worst case that should just result on a server-side error
        // instead of a friendlier client-side error
        QueueSaveState queueSaveState;
        string associatedPlaylistName;
        MusicQueueScreen.ParseQueueSaveState(_queueSaveStateNode, out queueSaveState, out associatedPlaylistName);
        bool isSavedPlaylist = !String.IsNullOrEmpty(associatedPlaylistName) &&
            String.Equals(PlaylistName, associatedPlaylistName, StringComparison.CurrentCultureIgnoreCase);

        // disable Save if another playlist has the entered playlist name already
        if (_existingPlaylistNames.ContainsKey(PlaylistName) && !isSavedPlaylist)
        {
            SaveButton.IsEnabled = false;
            CannotSaveMessage.Text = "Cannot save because a playlist has this name already.  To overwrite that playlist, delete it first.";
            return;
        }

        // otherwise, enable Save
        SaveButton.IsEnabled = true;
        CannotSaveMessage.Text = String.Empty;
    }

    string PlaylistName
    {
        get
        {
            return PlaylistNameTextBox.Text.Trim();
        }
    }

    private void PlaylistNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        UpdateSaveEnabledState();
    }

    private void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        string playlistName = PlaylistName;
        if (playlistName.Length > 0)
        {
            string command = ParsedSyncNodeCommand.Format("SaveQueue",
                "RecipientId", XmlConvert.ToString(_musicClientHelper.RecipientId),
                "PlaylistName", playlistName);

            SaveButton.IsWaiting = true;
            _musicClientHelper.WaitForMusicDeviceNode(delegate
            {
                SaveButton.IsWaiting = false;
                _musicClientHelper.GoToMusicScreen("Queue");
            });

            _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);
        }
    }

    private void Keyboard_EnterClick(object sender, RoutedEventArgs e)
    {
        if (SaveButton.IsEnabled)
            SaveButton_Click(null, null);
    }

    private void PlaylistNameTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            Keyboard_EnterClick(null, null);
            e.Handled = true;
        }
    }
}

}

